package xyz.lisys.controller;

import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.apache.commons.io.IOUtils;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.*;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import xyz.lisys.domain.po.CedUserPo;
import xyz.lisys.service.AsyncService;
import xyz.lisys.service.CedUserService;

import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

@Slf4j
@RestController
@RequestMapping("/component")
public class ComponentController {

    @Resource
    public RedisTemplate<String, Object> redisTemplate;

    @Resource
    public CedUserService cedUserService;

    @Resource
    public SqlSessionFactory sqlSessionFactory;

    @Resource
    public SqlSessionTemplate sqlSessionTemplate;

    @Autowired
    RequestMappingHandlerMapping requestMappingHandlerMapping;

    @Resource
    public AsyncService asyncService;

    @GetMapping("/param1")
    public ResponseEntity<HashMap<String, Object>> param1() {
        // redisTemplate使用

        JedisConnectionFactory jedisConnectionFactory = (JedisConnectionFactory) redisTemplate.getConnectionFactory();
        log.info(String.valueOf(jedisConnectionFactory.getPoolConfig().getMaxIdle()));

        val map = new HashMap<String, Object>();
        redisTemplate.opsForValue().set("component", "ComponentController");
        map.put("value", redisTemplate.opsForValue().get("component"));
        return ResponseEntity.ok(map);
    }

    @GetMapping("/param2")
    public ResponseEntity<List<CedUserPo>> param2() {
        // Dao层操作数据库

        return ResponseEntity.ok(cedUserService.selectAll());
    }

    @GetMapping("/param3")
    public ResponseEntity<String> param3() {
        // 事务回滚

        log.info("param3");
        try {
            if (Math.random() < 0.6) {
                cedUserService.insertUser();
            } else {
                cedUserService.insertUserException();
            }
        } catch (Exception ignored) {
            return ResponseEntity.ok("error");
        }
        return ResponseEntity.ok("ok");
    }

    @PostMapping("/param4")
    public String param4() {
        // 构建一个响应的cookie值，即Set-Cookie的值

        String cookie = ResponseCookie.from("foo", "bar")
                .httpOnly(true)
                .build()
                .toString();
        log.info(cookie);
        return "index";
    }

    @RequestMapping("/param5")
    public String param5() {
        // 状态码常量
        log.info(String.valueOf(HttpURLConnection.HTTP_OK));

        // 状态码常量
        log.info(String.valueOf(HttpStatus.OK.value()));

        // 请求头key值
        log.info(HttpHeaders.AUTHORIZATION);

        // 获取 mime 的类型常量
        log.info(MediaType.APPLICATION_JSON_VALUE);

        // 构建 Content-Disposition 请求头
        log.info(String.valueOf(ContentDisposition.attachment().filename("a.txt").build()));

        return "index";
    }

    @RequestMapping("/param6")
    public String param6() {
        // 从数据源[dataSource]获取一个数据库连接

        String result = "0";

        // com.alibaba.druid.pool.DruidDataSource
        log.info(sqlSessionFactory.getConfiguration().getEnvironment().getDataSource().getClass().getName());

        // org.mybatis.spring.transaction.SpringManagedTransactionFactory
        log.info(sqlSessionFactory.getConfiguration().getEnvironment().getTransactionFactory().getClass().getName());

        try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
            try {
                if (sqlSession.getConnection().getAutoCommit()) {
                    result = "1";
                }
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }

        return result;
    }

    @RequestMapping("/param7")
    public String param7() {
        Map<RequestMappingInfo, HandlerMethod> handlerMethods = requestMappingHandlerMapping.getHandlerMethods();

        // 遍历请求映射信息
        for (Map.Entry<RequestMappingInfo, HandlerMethod> entry : handlerMethods.entrySet()) {
            RequestMappingInfo mappingInfo = entry.getKey();
            HandlerMethod handlerMethod = entry.getValue();

            // 打印URL和对应的实例方法信息
            System.out.println("URL Patterns: " + mappingInfo.getPatternsCondition().getPatterns());
            System.out.println("HTTP Methods: " + mappingInfo.getMethodsCondition().getMethods());
            System.out.println("Handler Method: " + handlerMethod.getBeanType().getName() + "." + handlerMethod.getMethod().getName());
            System.out.println("------------------------");
        }

        return "index";
    }

    @GetMapping("/param8")
    public String param8() throws InterruptedException {
        asyncService.sleep();
        return "ok";
    }

    @GetMapping(value = "/param9")
    @SneakyThrows
    public void param9(HttpServletResponse response) {
        // 图片转发

        HttpURLConnection conn;
        InputStream in = null;
        ServletOutputStream out = null;

        URL url = new URL("");

        conn = (HttpURLConnection) url.openConnection();
        conn.setRequestMethod("GET");
        conn.connect();

        if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
            in = conn.getInputStream();
            out = response.getOutputStream();
            IOUtils.copy(in, out);
        }

        IOUtils.closeQuietly(in);
        conn.disconnect();

        if (out != null) {
            out.flush();
        }
    }

    @GetMapping("/param10")
    @SneakyThrows
    public void param10(HttpServletResponse response) {
        // 五个图片的下载地址，需替换为实际地址
        String[] imageUrls = {
                "http://gips0.baidu.com/it/u=3602773692,1512483864&fm=3028&app=3028&f=JPEG&fmt=auto?w=960&h=1280",
                "http://gips0.baidu.com/it/u=3602773692,1512483864&fm=3028&app=3028&f=JPEG&fmt=auto?w=960&h=1280",
                "http://gips0.baidu.com/it/u=3602773692,1512483864&fm=3028&app=3028&f=JPEG&fmt=auto?w=960&h=1280",
                "http://gips0.baidu.com/it/u=3602773692,1512483864&fm=3028&app=3028&f=JPEG&fmt=auto?w=960&h=1280",
                "http://gips0.baidu.com/it/u=3602773692,1512483864&fm=3028&app=3028&f=JPEG&fmt=auto?w=960&h=1280"
        };

        response.setContentType("application/zip");
        response.setHeader("Content-Disposition", "attachment; filename=images.zip");

        try (ZipOutputStream zipOut = new ZipOutputStream(response.getOutputStream())) {
            for (int i = 0; i < imageUrls.length; i++) {
                URL url = new URL(imageUrls[i]);
                HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                conn.setRequestMethod("GET");
                conn.connect();

                if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
                    try (InputStream in = conn.getInputStream()) {
                        ZipEntry zipEntry = new ZipEntry("image" + (i + 1) + ".jpg");
                        zipOut.putNextEntry(zipEntry);
                        byte[] buffer = new byte[4096];
                        int bytesRead;
                        while ((bytesRead = in.read(buffer)) != -1) {
                            zipOut.write(buffer, 0, bytesRead);
                        }
                        zipOut.closeEntry();
                    }
                }
                conn.disconnect();
            }
        }
    }
}
